home *** CD-ROM | disk | FTP | other *** search
/ Ian & Stuart's Australian Mac 1993 September / September 93.iso / Archives / Utilities / System / FKey / FKeys / Quickeys / SetQuicText.c < prev   
Encoding:
C/C++ Source or Header  |  1987-10-28  |  8.0 KB  |  272 lines  |  [TEXT/QED1]

  1. /*
  2.   * SetQuicText:        Hypercard XCMD to set up a text QuicKey with a text string of up to 72 characters.
  3.   *                    Usage:  SetQuicText modifiers, virtual key, text
  4.   *                    Modifiers can be one or more of "C" (Command), "L" (CapsLock), "O" (Option),
  5.   *                    "c" (Control), and "S" (Shift).
  6.   *                    The virtual key is a hardware-independent method of identifying a key. There's a
  7.   *                    table of key/char equivalences in Inside Macintosh Volume V, and also in the stack
  8.   *                    distributed with the PostEvent XCMD.
  9.   *                    Note that the text key has to be defined before this XCMD is run - i.e. the slot has
  10.   *                    to be reserved, and is assumed to be universal rather than program-specific (the
  11.   *                    XCMD looks at both, but checks universal first).
  12.   *                    Dewi Williams. Delphi: Dewi.
  13.   */
  14.  
  15. #include    <MemoryMgr.h>
  16. #include    <EventMgr.h>
  17. #include    <HyperXCmd.h>            /* Defines and structures for HyperCard XCMD programming */
  18. #include    <Environs.h>            /* Defines for the SysEnvirons trap */
  19. #include    <ScriptMgr.h>            /* Came with the 2.11 upgrade as "xScriptMgr.h" */
  20. #include    "QuicKeys.h"            /* Defines and structures for QuicKeys internals access */
  21.  
  22. #define    NULL        0L
  23. #define    HiWord(x)        (((unsigned short *)&(x))[0])
  24. #define    LoWord(x)        (((unsigned short *)&(x))[1])
  25. #define    controlKey    4096
  26.  
  27. /* Forward references */
  28. QuicInitBlock    *FindSysHeap();
  29. int            CalcModifiers(StringPtr str);
  30. int            CalculateCharCode(int modifiers, int theKey);
  31. Boolean        UpdateKeySlot(QuicInitBlock *qb, int kcode, int modifiers, StringPtr text);
  32.  
  33. pascal void
  34. main(paramPtr)
  35. XCmdBlockPtr    paramPtr;
  36. {
  37.     Str255            text;
  38.     QuicInitBlock        *qb;
  39.     int                theKey;
  40.     int                 modifiers;
  41.     SysEnvRec        env;
  42.     int                kcode;
  43.  
  44.     /* Ensure that this is system 4.1 or later.  This is needed for KeyTrans and extended keyboard
  45.       * checks. It ensures that KCHR/KMAP keyboard mappings are in place.
  46.       */
  47.     if (SysEnvirons(1, &env) == envNotPresent) {
  48.         /* We beep rather than put up an error message because I don't like hardwiring English
  49.           * strings into programs, and haven't figured out an owned resource type of technique for
  50.           * putting the error messages into resources. Apple needs to set a standard here (minor editorial!).
  51.           */
  52.         SysBeep(1);
  53.         return;
  54.     }
  55.  
  56.     /* There should be 3 parameters. */
  57.     if (paramPtr->paramCount != 3) {
  58.         SysBeep(1);
  59.         return;
  60.     }
  61.  
  62.     /* Find QuicKeys in the system heap. */
  63.     if ( (qb = FindSysHeap()) == NULL) {
  64.         /* Not running QuicKeys */
  65.         SysBeep(1);
  66.         return;
  67.     }
  68.  
  69.     /* First param is the modifiers.  Convert it to a pascal string */
  70.     ZeroToPas(paramPtr,*(paramPtr->params[0]), text);
  71.     
  72.     modifiers = CalcModifiers(text);
  73.  
  74.     /* If the control key is specified, see if this is possible with the current keyboard. */
  75.     if (modifiers&controlKey) {
  76.         /* Make no assumptions about new keyboard models! */
  77.         if (env.keyBoardType <= envStandADBKbd && env.keyBoardType != envAExtendKbd) {
  78.             SysBeep(1);
  79.             return;
  80.         }
  81.     }
  82.  
  83.     /* The second param is the virtual keycode.  */
  84.     ZeroToPas(paramPtr,*(paramPtr->params[1]), text);
  85.     theKey = ((int)StrToNum(paramPtr, (Str31 *)text)) & 0x7F;
  86.  
  87.     /* Sanity check: virtual keycodes past 0x60 belong to the extended keyboard (function keys, PageUp
  88.       * etc. To stop any possible confusion, we check for the existence of the extended keyboard before
  89.       * posting any such event.
  90.       */
  91.     if (theKey > 0x60 && env.keyBoardType != envAExtendKbd) {
  92.         SysBeep(1);
  93.         return;
  94.     }
  95.  
  96.     /* Third parameter is the text to substitute. */
  97.     ZeroToPas(paramPtr,*(paramPtr->params[2]), text);
  98.  
  99.     /* Clamp the string if it's too big. */
  100.     if (text[0] > 71) text[0] = 71;            /* with room for the length byte */
  101.     
  102.     if ( (kcode = CalculateCharCode(modifiers, theKey)) == 0) {
  103.         /* Bad virtual keycode? */
  104.         SysBeep(1);
  105.         return;
  106.     }
  107.  
  108.     if (UpdateKeySlot(qb, kcode, modifiers, text) == FALSE) {
  109.         /* Slot wasn't reserved in universal key area. */
  110.         SysBeep(1);
  111.     }
  112. }
  113.  
  114. /*
  115.   * This is a  C version of the example code in Chapter 8 of the QuicKeys manual.
  116.   */
  117.  
  118. QuicInitBlock *
  119. FindSysHeap()
  120. {
  121.     register Ptr            endBlk = SysZone->bkLim;
  122.     register QuicInitBlock    *qp;
  123.     
  124.     qp = (QuicInitBlock *) &SysZone->heapData;
  125.  
  126.     while(qp != (QuicInitBlock *) endBlk) {
  127.         /* Analyze the block we're looking at. */
  128.         if ((qp->header[0] & 0xC0) == 0x40) {                /* Is it non-relocatable? */
  129.             /* Check magic and signature. */
  130.             if (qp->quic.magic == 0xa89f1234 && qp->quic.signature == 'CELN') {
  131.                 /* Chapter 8 states that the version number is 1. It's actually 0 (as the example
  132.                   * assembly language shows and a quick call to CE Software confirmed).
  133.                   */
  134.                 if (qp->quic.version == 0) return qp;
  135.             }
  136.         }
  137.  
  138.         /* Time to move on to the next block. The 0xFFFFFF strips off the tag byte(s). */
  139.         qp = (QuicInitBlock *)(((Byte *)qp) + ((* (long *)&qp->header) & 0xFFFFFF));
  140.     }
  141.     return NULL;        /* Failed to find it */
  142. }
  143.  
  144. /*
  145.   * CalculateCharCode:    given a virtual keycode value, calculate the keycode/charcode combination.
  146.   */
  147.  
  148. int
  149. CalculateCharCode(modifiers, theKey)
  150. int         modifiers;
  151. int        theKey;
  152. {
  153.     long                kResult;
  154.     long                state = 0;
  155.     Handle            hKeyData;
  156.     register int        kchrID;
  157.     int            theCode;
  158.  
  159.     /* Calculate the resource ID of the relevant KCHR resource. The Script Manager has
  160.       * this information. This may be useful if you're using Dvorak mappings, for instance.
  161.       * I haven't really been able to test this - 0 is the US default, and it's the only one I
  162.       * have.
  163.       */
  164.     kchrID = (int)GetScript(GetEnvirons(smKeyScript), smScriptKeys);
  165.  
  166.     if ( (hKeyData = GetResource('KCHR', kchrID)) == NULL) {
  167.         /* We've confirmed that it is System 4.1 or later. Strange. */
  168.         SysBeep(1);
  169.         return;
  170.     }
  171.  
  172.     /* The keyCode parameter passed to the KeyTrans trap consists of the modifier
  173.       * flags in bits 8-15, up/down stroke in bit 7 (1 = up), and the virtual key
  174.       * code in bits 6 - 0. 
  175.       */
  176.     modifiers |= btnState;                    /* The mouse button is UP */
  177.     theKey |= modifiers;                        /* Already in bits 8-15 */
  178.  
  179.     /* I'm assuming here that KeyTrans doesn't move the heap. Don't see why it should. */
  180.     if ( (kResult = KeyTrans(*hKeyData, theKey, &state)) == 0) return 0;
  181.  
  182.     /* kResult consists of 2 16 bit characters to be posted as events (usually the high word of each is 0),
  183.       * high word first. A return value of 0 in either word should not be posted. 
  184.       */
  185.     if ((theCode = HiWord(kResult)) != 0) {
  186.         if (LoWord(kResult) != 0) {
  187.             /* This combination's inappropriate - it has to be a single keycode/charcode combination.  */
  188.             return 0;
  189.         }
  190.     } else {
  191.         theCode = LoWord(kResult);
  192.     }
  193.  
  194.     theKey &= 0x7F;            /* Cut out any modifiers */
  195.     theKey <<= 8;                /* And shift to the keyCode position */
  196.     theCode |= theKey;
  197.  
  198.     return theCode;
  199. }
  200.  
  201. /* Convert the modifier string to its numeric equivalent. This code isn't perfect - it does
  202.   * blind matches without validating for odd characters. For instance "LXO" == "LO".
  203.   */
  204.  
  205. static int
  206. CalcModifiers(str)
  207. register StringPtr    str;
  208. {
  209.     register StringPtr    end = str + str[0] + 1;
  210.     register int    modifiers =  0;
  211.  
  212.     for (str++;str < end; str++) {
  213.         switch( (*str) ) {
  214.         case 'C':
  215.             modifiers |= cmdKey;
  216.             break;
  217.         case 'S':
  218.             modifiers |= shiftKey;
  219.             break;
  220.         case 'L':
  221.             modifiers |= alphaLock;
  222.             break;
  223.         case 'O':
  224.             modifiers |= optionKey;
  225.             break;
  226.         case 'c':
  227.             modifiers |= controlKey;
  228.             break;
  229.         }
  230.     }
  231.     return modifiers;
  232. }
  233.  
  234. /*
  235.   * Write "theText" into the QuicKeys text key slot identified by "kcode". Look in universal first, then
  236.   * in program-specific.
  237.   */
  238.  
  239. Boolean
  240. UpdateKeySlot(qb, kcode, modifiers, theText)
  241. QuicInitBlock    *qb;
  242. int            kcode;
  243. int            modifiers;
  244. StringPtr        theText;
  245. {
  246.     register KeyRecord    *kr = qb->quic.universal;
  247.     register KeyRecord    *end = kr + N_QCKEYS;
  248.  
  249.     for (; kr < end; kr++) {
  250.         if (kr->QKtype == QK_TEXT) {
  251.             if ((kr->key) == kcode && (kr->modifiers == modifiers)) {
  252.                 BlockMove(theText, kr->u.QuicText.text, (Size)(theText[0] + 1));
  253.                 return TRUE;
  254.             }
  255.         }
  256.     }
  257.  
  258.     /* Can't find it in universal, so let's look in program-specific for Hypercard. */
  259.     kr = qb->quic.application;
  260.     end = kr + N_QCKEYS;
  261.  
  262.     for (; kr < end; kr++) {
  263.         if (kr->QKtype == QK_TEXT) {
  264.             if ((kr->key) == kcode && (kr->modifiers == modifiers)) {
  265.                 BlockMove(theText, kr->u.QuicText.text, (Size)(theText[0] + 1));
  266.                 return TRUE;
  267.             }
  268.         }
  269.     }
  270.     return FALSE;
  271. }
  272.